package com.fingard.dsp.bank.directbank.pab01;

import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptData;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptDataHelper;
import com.fingard.dsp.bank.directConfig.ReceiptProConfig;
import com.fingard.dsp.bank.directbank.bankInterface.IReceiptPro;
import com.fingard.dsp.bank.reqrespobj.downloadreceipt.ReqQryReceipt;
import com.fingard.dsp.bank.reqrespobj.downloadreceipt.RetAtsReceipt;
import com.fingard.dsp.bank.sepro.ReceiptPro;
import com.fingard.io.FileHelper;
import com.fingard.text.StringHelper;
import com.fingard.util.ZipHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

public class PAB01ReceiptPro extends PAB01Base implements IReceiptPro {

    @Override
    public RetAtsReceipt qryReceiptOneDay(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay)
            throws Exception {
        ReceiptDataHelper receiptHelper = null;//回单数据保存类，分区分表
        String qryDay = Format.Date10Format.format(pOneDay);
        List<String> fileList = new ArrayList<String>();
        try {
            receiptHelper = new ReceiptDataHelper(pReqReceipt.reqHeader.tenant, pOneDay);
            writeInfoLog(String.format("开始查询账号【%s】在日期【%s】的回单明细", pReqReceipt.actNum, qryDay));
            qryReceiptInfo(receiptHelper, pReqReceipt, pOneDay);
            List<String> istNbrList = receiptHelper.getIstNbrList(pReqReceipt.actNum, pOneDay);
            if (istNbrList == null || istNbrList.size() == 0) {
                return null;
            }
            writeInfoLog(String.format("开始下载账号【%s】在日期【%s】的回单文件", pReqReceipt.actNum, qryDay));
            fileList = downloadFile(pConfig, pReqReceipt, pOneDay);
            writeInfoLog(String.format("开始对账号【%s】在日期【%s】的回单明细和文件进行匹配", pReqReceipt.actNum, qryDay));
            if (fileList.size() != 0) {
                for (String fileName : fileList) {
                    receiptMatch(receiptHelper, pConfig, pReqReceipt, pOneDay, fileName);
                }
            }
        } catch (Exception ex) {
            WriteBankLogLn(ex);
        } finally {
            receiptHelper.close();
            for (String zipPath : fileList) {
                boolean delFlag = FileHelper.deleteRecursive(zipPath);
                if (delFlag) {
                    writeInfoLog("删除文件：" + zipPath + "成功");
                } else {
                    writeErrorLog("删除文件：" + zipPath + "失败");
                }
            }
        }
        return null;
    }

    private void receiptMatch(ReceiptDataHelper receiptHelper, ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay, String fileName) {
        String[] filenameAndExt = StringHelper.splitFileNameAndExt(fileName);
        String tmpReceiptPath = pConfig.getSaveSubDir(pReqReceipt.reqHeader, pOneDay) + File.separator + Format.Date10Format.format(pOneDay) + File.separator + ReceiptPro.getTransID()
                + filenameAndExt[0];
        try {
            FileHelper.mkdir(tmpReceiptPath);
            writeInfoLog("开始解压文件" + fileName + "至临时文件夹" + tmpReceiptPath);
            ZipHelper.unZipFiles(fileName, tmpReceiptPath);
            File tmpReceiptDir = new File(tmpReceiptPath);
            String receiptDirRelPath = pConfig.getRelativeSaveDir(reqHeader, pOneDay) + File.separator + pReqReceipt.actNum + File.separator + Format.Date10Format.format(pOneDay);

            if (tmpReceiptDir.exists() && tmpReceiptDir.listFiles().length != 0) {
                for (File pdfFile : tmpReceiptDir.listFiles()) {
                    String pdfFileName = pdfFile.getName();
                    String istNbr = pdfFileName.substring(0, pdfFileName.lastIndexOf("_"));
                    ReceiptData receiptData = receiptHelper.loadFromDbByIstNbr(pReqReceipt.actNum, istNbr);
                    if (receiptData == null) {
                        writeErrorLog(String.format("回单文件【%s】没有匹配到对应的明细，请核查!", pdfFileName));
                    } else if (!"2".equals(receiptData.downState)) {
                        String pdfRelPath = receiptDirRelPath + File.separator + pdfFileName;
                        String pdfAbsPath = pConfig.localSaveMainDir + File.separator + pdfRelPath;
                        FileHelper.copyFile(pdfFile.getAbsolutePath(), pdfAbsPath);
                        //下载回单文件
                        if (FileHelper.existFile(pdfAbsPath)) {
                            int rowAff = receiptHelper.updateDownState(pReqReceipt.actNum, receiptData.istNbr, pdfRelPath, pdfFile.getName(), "2");
                            writeInfoLog(String.format("回单编号【%s】与回单文件【%s】匹配成功\n文件保存地址：%s", pReqReceipt.actNum, pdfFile.getName(), pdfAbsPath));
                            writeInfoLog("影响数据库行数：" + rowAff);
                        } else {
                            writeErrorLog(String.format("回单编号【%s】与回单文件【%s】匹配失败", pReqReceipt.actNum, pdfFile.getName()));
                        }
                    } else {
                        writeErrorLog(String.format("回单文件【%s】先前已经匹配成功", pReqReceipt.actNum, pdfFile.getName()));
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            writeErrorLog(ex.getMessage());
        } finally {
            boolean delFlag = FileHelper.deleteRecursive(tmpReceiptPath);
            if (delFlag) {
                writeInfoLog("删除文件：" + tmpReceiptPath + "成功");
            } else {
                writeErrorLog("删除文件：" + tmpReceiptPath + "失败");
            }
        }
    }

    private List<String> downloadFile(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay) {
        List<String> filelist = new ArrayList<String>();
        //下载逐笔回单
        String fileName = downloadFile(pConfig, pReqReceipt, pOneDay, "ELC002");
        if (StringHelper.hasAnyChar(fileName)) {
            filelist.add(fileName);
        }
        //下载汇总回单，所有的回单在一张pdf中展示
//         fileName = downloadFile(pConfig,pReqReceipt,pOneDay,"F00101");
//        if(StringHelper.hasAnyChar(fileName)){
//            filelist.add(fileName);
//        }
        return filelist;
    }

    private String downloadFile(ReceiptProConfig pConfig, ReqQryReceipt pReqReceipt, Date pOneDay, String trncode) {
        try {
            PAB01Header bankHeader = new PAB01Header();
            bankHeader.trncode = trncode;
            bankHeader.fourZero = "0000";
            bankHeader.reqSeqNo = getQryTransID();
            XmlTextWriter xmlWriter = new XmlTextWriter();
            xmlWriter.autoFormat = false;
            writeCommonHeader(xmlWriter);
            xmlWriter.writeStartElement("Result");
            xmlWriter.writeElementString("Account", pReqReceipt.actNum);
            xmlWriter.writeElementString("QueryDate", Format.Date8Format.format(pOneDay));
            xmlWriter.writeEndDocument();
            FGBiz.logTrace.info(this.getLogCode(), "发送银行报文:\r\n:" + xmlWriter.toXmlString());
            String[] tmpStrRet = sendToBank(xmlWriter.toXmlString(), bankHeader);
            FGBiz.logTrace.info(this.getLogCode(), "银行返回结果:\r\n:" + Arrays.toString(tmpStrRet));

            if (tmpStrRet[0].length() == 0 && StringHelper.hasAnyChar(tmpStrRet[1])) {
                String retCode = tmpStrRet[2];
                if ("000000".equals(retCode) && tmpStrRet[1].contains("<")) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1].substring(tmpStrRet[1].indexOf('<')), tmpSbMsg);
                    if (tmpBkReader != null) {
                        DownloadFile download = new DownloadFile(this.reqHeader, this.bankFront, this.sbLog);
                        while (tmpBkReader.read("/Result")) {

                            DownFileReq req = new DownFileReq(tmpBkReader.readedXElement);
                            String saveDirPathTemp = pConfig.getSaveSubDir(pReqReceipt.reqHeader, pOneDay) + File.separator + Format.Date10Format.format(pOneDay) + File.separator + ReceiptPro.getTransID();
                            //String filePath = StringHelper.trimEnd(bankFront.bankReceiptMainDir, "/");

                            req.filePath = saveDirPathTemp;
                            //下载文件
                            DownFileResp resp = download.downFile(req);
                            if (resp.execResult) {
                                return req.filePath + File.separator + req.fileName;
                            }
                        }
                    } else {
                        writeErrorLog(tmpSbMsg.toString());
                    }
                } else {
                    writeErrorLog("银行返回的格式不正确");
                }
            } else {
                writeErrorLog(tmpStrRet[1]);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            writeErrorLog(ex.getMessage());
        }
        return "";
    }

    private void qryReceiptInfo(ReceiptDataHelper receiptHelper, ReqQryReceipt pReqReceipt, Date pOneDay) throws Exception {
        PAB01Header bankHeader = new PAB01Header();
        bankHeader.trncode = "ELC001";
        bankHeader.fourZero = "0000";
        int startRecord = 1;//起始值为1，不能送0
        boolean hasNextPage = false;
        do {//分页查询
            XmlTextWriter xmlWriter = new XmlTextWriter();
            xmlWriter.autoFormat = false;
            writeCommonHeader(xmlWriter);
            xmlWriter.writeStartElement("Result");
            xmlWriter.writeElementString("AcctNo", pReqReceipt.actNum);
            xmlWriter.writeElementString("ReceiptType", "ALL");//回单类型
            xmlWriter.writeElementString("SubType", "ALL");//子类型
            xmlWriter.writeElementString("StartDate", Format.Date8Format.format(pOneDay));//起始日期 格式yyyyMMdd（记账日期）
            xmlWriter.writeElementString("EndDate", Format.Date8Format.format(pOneDay));//结束日期
            xmlWriter.writeElementString("StartRecord", startRecord + "");//起始值为1，不能送0
            xmlWriter.writeElementString("RecordNum", 20 + "");//本批记录数
            xmlWriter.writeElementClosed("StartAmt");//非必输，开始金额
            xmlWriter.writeElementClosed("EntAmt");//非必输，结束金额
            /*001：交易时间从近到远   002：交易时间从远到近   003：金额升序（从小到大）   004：金额降序（从大到小）   005：回单号升序   006：回单号降序*/
            xmlWriter.writeElementClosed("OrderMode");//非必输，排序方式
            xmlWriter.writeElementClosed("PayeeAcctNo");//非必输，收款人账号
            xmlWriter.writeElementClosed("PayeeName");//非必输，收款人名称
            xmlWriter.writeElementClosed("DrCrFlag");//非必输，借贷标志
            xmlWriter.writeElementClosed("Ccy");//非必输，币种
            xmlWriter.writeElementClosed("SerialNo");//非必输，顺序号
            xmlWriter.writeElementClosed("PrintBranchId");//非必输，打印网点
            xmlWriter.writeElementClosed("ReceiptNo");//非必输，回单号
            xmlWriter.writeElementClosed("PrintFlag");//非必输，打印标志，0：首次打印      1：补打
            xmlWriter.writeEndDocument();
            hasNextPage = false;
            bankHeader.reqSeqNo = getQryTransID();
            FGBiz.logTrace.info(this.getLogCode(), "发送银行报文:\r\n:" + xmlWriter.toXmlString());
            String[] tmpStrRet = sendToBank(xmlWriter.toXmlString(), bankHeader);
            FGBiz.logTrace.info(this.getLogCode(), "银行返回结果:\r\n:" + Arrays.toString(tmpStrRet));
            if (tmpStrRet[0].length() == 0 && StringHelper.hasAnyChar(tmpStrRet[1])) {
                String retCode = tmpStrRet[2];
                String retInfo = tmpStrRet[3];
                if ("000000".equals(retCode)) {
                    if (tmpStrRet[1].contains("<")) {
                        StringBuilder tmpSbMsg = new StringBuilder();
                        XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1].substring(tmpStrRet[1].indexOf('<')), tmpSbMsg);
                        if (tmpBkReader != null) {
                            //Y:无剩余记录  N:有剩余记录
                            String endFlag = tmpBkReader.getFirstText("/Result/EndFlag").toUpperCase();
                            if ("Y".equals(endFlag)) {
                                hasNextPage = true;
                            }
                            while (tmpBkReader.read("/Result/list")) {
                                startRecord++;
                                ReceiptData receiptData = new ReceiptData();
                                receiptData.bank = "307";
                                receiptData.srcSys = this.bankFront.bankCode;
                                receiptData.ownAct = pReqReceipt.actNum;
                                receiptData.cur = pReqReceipt.actCur;
//                                RemarkCode	Char(15)	摘要码
                                String remarkCode = tmpBkReader.readedXElement.getSingleText("RemarkCode");
//                                ReceiptNo	Char(32)	回单号，pro模式上传回单文件时会将回单文件按照receiptNo来命名后上传，平安银行回单单笔交易会产生
                                //交易和手续费两个回单，流水号相同，区别在RemarkCode这个字段，在此通过这个字段来区分手续费
                                receiptData.receiptNo = tmpBkReader.readedXElement.getSingleText("HostSeqNo") + remarkCode;
//                                ReceiptType	Char(10)	回单类型
//                                PayerName	Char(300)	付款人名称
//                                PayeeName	Char(300)	收款人名称
//                                PayerAccNo	Char(50)	付款人账号
//                                PayeeAccNo	Char(50)	收款人账号
//                                TranAmt	Double(20,4)交易金额
                                receiptData.amount = new BigDecimal(tmpBkReader.readedXElement.getSingleText("TranAmt"));
//                                DrCrFlag	Char(4)	借贷标志
                                String dcFlag = tmpBkReader.readedXElement.getSingleText("DrCrFlag");
                                if ("C".equals(dcFlag)) {
                                    receiptData.moneyWay = "2";
                                    receiptData.oppActNum = tmpBkReader.readedXElement.getSingleText("PayerAccNo");
                                    receiptData.oppActName = tmpBkReader.readedXElement.getSingleText("PayerName");
                                } else {
                                    receiptData.moneyWay = "1";
                                    receiptData.oppActNum = tmpBkReader.readedXElement.getSingleText("PayeeAccNo");
                                    receiptData.oppActName = tmpBkReader.readedXElement.getSingleText("PayeeName");
                                }
//                                TranDate	Char(8)	交易日期
                                receiptData.busDate = Integer.valueOf(tmpBkReader.readedXElement.getSingleText("TranDate"));
//                                HostSeqNo	Char(52)	主机流水号
                                String hostSeqNo = tmpBkReader.readedXElement.getSingleText("HostSeqNo");
//                                回单文件的命名规则:账号_日期_流水号_借贷_摘要_明细序号.pdf,所以通过账号_日期_流水号_借贷_摘要去匹配
                                receiptData.istNbr = receiptData.ownAct + "_" + receiptData.busDate + "_" + hostSeqNo + "_" + dcFlag + "_" + remarkCode;
                                int inRe = receiptHelper.insertIfNotExist(receiptData, true);
                                if (inRe == 1) {
                                    writeInfoLog("回单编号:" + receiptData.istNbr + "写入数据库，影响行数：" + inRe);
                                } else if (inRe == 0) {
                                    writeInfoLog("回单编号:" + receiptData.istNbr + "更新数据库，影响行数：" + inRe);
                                }
                            }
                        } else {
                            writeInfoLog(tmpSbMsg.toString());
                        }
                    } else {
                        writeInfoLog("银行返回报文格式非法");
                    }
                } else {
                    writeInfoLog(retInfo);
                }
            } else {
                writeInfoLog(tmpStrRet[1]);
            }
        } while (hasNextPage);
    }


    public void writeInfoLog(String msg) {
        WriteBankLogLn(msg);
        FGBiz.logTrace.info(this.getLogCode(), msg);
    }

    public void writeErrorLog(String msg) {
        WriteBankLogLn(msg);
        FGBiz.logTrace.error(this.getLogCode(), msg);
    }
}
